type svalue = Tokens.svalue
type pos = int
type ('a, 'b) token = ('a, 'b) Tokens.token
type lexresult = (svalue,pos) token


val lineNum = ErrorMsg.lineNum
val linePos = ErrorMsg.linePos
val comsnum= ref 0(* number of comments*)
val str= ref "" (* string that is read symbol by symbol*)
val strbegin= ref 0 (* position of the beginning of the string*)


fun err(p1,p2) = ErrorMsg.error p1

fun eof() = let val pos = hd(!linePos) in if !comsnum<>0 then ErrorMsg.error pos("unclosed comments") else comsnum:= !comsnum;  Tokens.EOF(pos,pos) end;

%% 
%header (functor TigerLexFun(structure Tokens : Tiger_TOKENS));
%s COMMENT STRING INITIAL; 


%%

<INITIAL,COMMENT>\n	=> (lineNum := !lineNum+1; linePos := yypos :: !linePos; continue());
<INITIAL>[\ \t]+ => (continue());

<INITIAL>array  => (Tokens.ARRAY(yypos,yypos+5));
<INITIAL>break	=> (Tokens.BREAK(yypos,yypos+5));
<INITIAL>do 	=> (Tokens.DO(yypos,yypos+2));
<INITIAL>else  	=> (Tokens.ELSE(yypos,yypos+4));
<INITIAL>end  	=> (Tokens.END(yypos,yypos+3));
<INITIAL>for  	=> (Tokens.FOR(yypos,yypos+3));
<INITIAL>function  	=> (Tokens.FUNCTION(yypos,yypos+8));
<INITIAL>if  	=> (Tokens.IF(yypos,yypos+2));
<INITIAL>in  	=> (Tokens.IN(yypos,yypos+2));
<INITIAL>let  	=> (Tokens.LET(yypos,yypos+3));
<INITIAL>nil 	=> (Tokens.NIL(yypos,yypos+3));
<INITIAL>of  	=> (Tokens.OF(yypos,yypos+2));
<INITIAL>to  	=> (Tokens.TO(yypos,yypos+2));
<INITIAL>then	=> (Tokens.THEN(yypos,yypos+4));
<INITIAL>type  	=> (Tokens.TYPE(yypos,yypos+4));
<INITIAL>var  	=> (Tokens.VAR(yypos,yypos+3));
<INITIAL>while	=> (Tokens.WHILE(yypos,yypos+5));

<INITIAL>"."	=> (Tokens.DOT(yypos,yypos+1));
<INITIAL>"+"	=> (Tokens.PLUS(yypos,yypos+1));
<INITIAL>"-"	=> (Tokens.MINUS(yypos,yypos+1));
<INITIAL>"*"	=> (Tokens.TIMES(yypos,yypos+1));
<INITIAL>"/"	=> (Tokens.DIVIDE(yypos,yypos+1));
<INITIAL>"="	=> (Tokens.EQ(yypos,yypos+1));
<INITIAL>"<>"	=> (Tokens.NEQ(yypos,yypos+2));
<INITIAL>"<"	=> (Tokens.LT(yypos,yypos+1));
<INITIAL>"<="	=> (Tokens.LE(yypos,yypos+2));
<INITIAL>">"	=> (Tokens.GT(yypos,yypos+1));
<INITIAL>">="	=> (Tokens.GT(yypos,yypos+2));
<INITIAL>"&"	=> (Tokens.AND(yypos,yypos+1));
<INITIAL>"|"	=> (Tokens.OR(yypos,yypos+1));
<INITIAL>":="	=> (Tokens.ASSIGN(yypos,yypos+2));


<INITIAL>"["	=> (Tokens.LBRACK(yypos,yypos+1));
<INITIAL>"]"	=> (Tokens.RBRACK(yypos,yypos+1));
<INITIAL>"{"	=> (Tokens.LBRACE(yypos,yypos+1));
<INITIAL>"}"	=> (Tokens.RBRACE(yypos,yypos+1));
<INITIAL>"("	=> (Tokens.LPAREN(yypos,yypos+1));
<INITIAL>")"	=> (Tokens.RPAREN(yypos,yypos+1));
<INITIAL>":"	=> (Tokens.COLON(yypos,yypos+1));
<INITIAL>";"	=> (Tokens.SEMICOLON(yypos,yypos+1));
<INITIAL>","	=> (Tokens.COMMA(yypos,yypos+1));


<INITIAL>[0-9][0-9]*=>(Tokens.INT(valOf(Int.fromString yytext),yypos,yypos+size yytext));
<INITIAL>[a-zA-Z][a-zA-Z0-9_]*=>(Tokens.ID(yytext,yypos,yypos+size yytext));
<INITIAL>\"=>(YYBEGIN STRING;str := ""; strbegin := yypos; continue());
<STRING>\\n=> (str := !str ^ "\n";continue());
<STRING>\\t=> (str := !str ^ "\t";continue());
<STRING>\\\"=> (str := !str ^ "\"";continue());
<STRING>\\\\=> (str := !str ^ "\\";continue());
<STRING>\\\^[A-Z@_^.]=> (str := !str^ Char.toString (chr( ord (List.nth(explode yytext,2)) -64)  ); continue());
<STRING>\\[0-9][0-9][0-9]=> (let val a= valOf(Int.fromString(String.substring(yytext,1,3))) in  str := !str ^  String.str(chr(a)) end;continue());



<STRING>\\[\n\t ]+\\ => (continue());																						
<STRING>\"=>(YYBEGIN INITIAL; Tokens.STRING(!str,!strbegin,!strbegin+size( !str) ));
<STRING>\\	=> ( ErrorMsg.error yypos "invalid escape character"
 ; continue()); 
<STRING>\n   => ( ErrorMsg.error yypos ("unclosed string" );  continue());
<STRING>.=>(str := !str^ yytext; continue());

<INITIAL>"/*"=>(YYBEGIN COMMENT;comsnum := 1;continue()) ;
<COMMENT>"/*"=> ( comsnum := !comsnum+1; continue());
<COMMENT>"*/"=> ( comsnum := !comsnum-1; if !comsnum =0 then (YYBEGIN INITIAL) else comsnum := !comsnum; continue());
<COMMENT>. => (continue());

<INITIAL>.  => (ErrorMsg.error yypos ("illegal character " ^ yytext); continue());